#include <iostream>
using namespace std;

/**
 * @brief 动物类
 * @note 基类
 */
class AnimalClass
{
public:
	///**
	// * @brief
	// * @note 地址早绑定，在编译阶段确认
	// * @note 如果想执行子类，那吗这个函数地址需要在运行阶段绑定
	// */
	//void speek()
	//{
	//	cout << "动物在说话" << endl;
	//}

	///**
	// * @brief 
	// * @note 虚函数
	// * @note 可以实现地址晚绑定
	// */
	//virtual void speek()
	//{
	//	cout << "动物在说话" << endl;
	//}

	/**
	 * @brief
	 * @note 纯虚函数
	 * @note 如果子类重写父类的纯虚函数，那么子类也是抽象类
	 * @note 有纯虚函数的类，叫抽象类，不可实例化对象
	 */
	virtual void speek() = 0;
};

/**
 * @brief 猫类
 */
class CatClass :public AnimalClass
{
public:
	/**
	 * @brief 
	 * @note 函数返回值类型 函数名 参数列表完全相同-重写
	 */
	void speek()
	{
		cout << "猫在说话" << endl;
	}
};

class DogClass :public AnimalClass
{
public:
	/**
	 * @brief 
	 * @note override 关键字，用来确保正确覆盖了虚函数
	 */
	void speek() override
	{
		cout << "狗在说话" << endl;
	}
};

/**
 * @brief 动物说话的函数
 * @param animal 动物
 * @note 将派生类（子类）对象的地址赋给基类（父类）指针，称为“向上转型”（Upcasting）
 * @note 这个过程是隐式的，不需要任何类型转换，是类型安全的。
 * @note 基类指针不能直接调用子类特有成员
 */
void doSpeek(AnimalClass& animal)
{
	animal.speek();
}

void test01()
{
	CatClass cat;
	doSpeek(cat);//允许

	DogClass dog;
	doSpeek(dog);

	AnimalClass* cat2 = new CatClass;
	doSpeek(*cat2);
}

int main(void)
{
	test01();
	return 0;
}